# frozen_string_literal: true

module Gitlab
  module VulnerabilityScanning
    module DependencyScanning
      class FindingBuilder < VulnerabilityScanning::FindingBuilder
        include Gitlab::Utils::StrongMemoize

        MissingPropertiesError = Class.new(StandardError)

        private

        def validate!
          return unless input_file.nil?

          raise MissingPropertiesError,
            'Missing required gitlab:dependency_scanning CycloneDX properties'
        end

        def report_type
          "dependency_scanning"
        end

        def title
          advisory.title
        end
        strong_memoize_attr :title

        def details
          {
            vulnerable_package: {
              name: "Vulnerable Package",
              type: "text",
              value: "#{affected_component.name}:#{affected_component.version}"
            }
          }.with_indifferent_access.freeze
        end

        def input_file
          sbom_source.input_file_path || sbom_source.source_file_path
        end
        strong_memoize_attr :input_file

        def location
          ::Gitlab::Ci::Reports::Security::Locations::DependencyScanning.new(
            file_path: input_file,
            package_name: affected_component.name,
            package_version: affected_component.version
          )
        end
        strong_memoize_attr :location

        def gemnasium_identifier
          {
            type: "gemnasium",
            value: advisory.xid,
            name: "Gemnasium-#{advisory.xid}"
          }.with_indifferent_access.freeze
        end
        strong_memoize_attr :gemnasium_identifier

        def identifiers
          # The gemnasium identifier is prepended for all dependency scanning
          # findings. This is required since it has historically been used
          # as the primary identifier for dependency scanning findings.
          # Creating findings without this would lead to new findings
          # appearing, i.e. it would incorrectly duplicate findings.
          # See https://gitlab.com/gitlab-org/gitlab/-/issues/417787
          [gemnasium_identifier]
            .concat(advisory.identifiers)
            .map do |identifier|
              ::Gitlab::Ci::Reports::Security::Identifier.new(
                external_type: identifier['type'],
                external_id: identifier['value'],
                name: identifier['name'],
                url: identifier['url'])
            end
        end
        strong_memoize_attr :identifiers

        def original_data
          {
            message: title,
            description: advisory.description,
            solution: advisory.solution,
            location: {
              file: input_file,
              dependency: {
                package: { name: affected_component.name },
                version: affected_component.version
              }
            }
          }.with_indifferent_access.freeze
        end
      end
    end
  end
end
